
/**
\file Specialisation of nmn::math::vector for booleans.
\author Sean Tromans
*/

#ifndef	NMN_TEMPLATES_MATH_VECTOR_BOOLEAN_HPP
#define	NMN_TEMPLATES_MATH_VECTOR_BOOLEAN_HPP

#include <needs_more_ninja/template/math/vector/vector.hpp>
#include <bitset>

#define NMN_MATH_VECTOR_CONSTRUCTOR( z, n, _ )	\
	vector( BOOST_PP_ENUM_PARAMS_Z(z, BOOST_PP_INC(n), bool p) );

namespace nmn
{

	namespace math
	{

		/**
		Boolean specialisation of the nmn::vector type.
		\author Sean Tromans
		*/
		template < size_t Size >
		class vector< bool, Size >	:	public	boost::equality_comparable1< typename vector< bool, Size > >
		{
			//
			//	Public Member Types
			//
			public:

				typedef	vector< bool, Size >		my_type;
				typedef std::bitset<Size>			bitset_type;
				typedef std::size_t					size_type;
				enum	{	static_size = Size	};

				typedef	bool							value_type;
				typedef	typename bitset_type::reference	reference_type;
				typedef	bool							const_reference_type;

				//typedef typename array_type::iterator				iterator;
				//typedef typename array_type::const_iterator			const_iterator;
				//typedef typename array_type::reverse_iterator		reverse_iterator;
				//typedef typename array_type::const_reverse_iterator	const_reverse_iterator;

			//
			//	Public Member Functions
			//
			public:

				/**
				Default Constructor. Does nothing.
				\author Sean Tromans
				*/
				vector( );

				/**
				Copy construct from another vector of the same size, but potentially a different type.
				@param rhs The vector to copy.
				\author Sean Tromans
				*/
				vector( my_type const & rhs );

				/**
				Set all components of the vector to the same inital value.
				@param rhs The value to initialise with.
				\author Sean Tromans
				*/
				vector( value_type const & rhs );

				BOOST_PP_REPEAT_FROM_TO( 1, NMN_MATH_VECTOR_MAX_ARITY, NMN_MATH_VECTOR_CONSTRUCTOR, 0 );

				/**
				Assign this vector to be equal to another.
				@param rhs The vector to copy.
				\author Sean Tromans
				*/
				my_type & operator = ( my_type const & rhs );

				/**
				The size of the vector.
				\author Sean Tromans
				*/
				size_type size( ) const;

				/**
				Test if all components of this vector are true.
				@return True if each component is true.
				\author Sean Tromans
				*/
				bool all( ) const;

				/**
				Test if all components of this vector equal another.
				@param rhs The vector to compare against.
				@return True if each corresponding component in the two vectors are exactly equal.
				\author Sean Tromans
				*/
				bool all( my_type const & rhs ) const;

				/**
				Test if any of the components of this vector are true.
				@return True if any component is true.
				\author Sean Tromans
				*/
				bool any( ) const;

				/**
				Test if any of the components of this vector equal another.
				@param rhs The vector to compare against.
				@return True if each corresponding component in the two vectors are exactly equal.
				\author Sean Tromans
				*/
				bool any( my_type const & rhs ) const;

				/**
				Gets a component from inside the vector.
				@param index The index of the component to return.
				@return a reference to the component at \c index.
				\author Sean Tromans
				*/
				reference_type operator[] ( size_type index );

				/**
				Gets a component from inside the vector.
				@param index The index of the component to return.
				@return a constant reference to the component at \c index.
				\author Sean Tromans
				*/
				const_reference_type operator[] ( size_type index ) const;

				/**
				Gets a component from inside the vector.
				@param index The index of the component to return.
				@return a reference to the component at \c index.
				\author Sean Tromans
				*/
				reference_type at( size_type index );

				/**
				Gets a component from inside the vector.
				@param index The index of the component to return.
				@return a constant reference to the component at \c index.
				\author Sean Tromans
				*/
				const_reference_type at( size_type index ) const;

				/**
				Swaps this vector with another.
				@param rhs The vector to swap with.
				\author Sean Tromans
				*/
				void swap( my_type & rhs );

				/**
				Converts the vector to a string.
				\author Sean Tromans
				*/
				std::string to_string( ) const;

			//
			//	Private Member Types
			//
			private:

				bitset_type m_bitset;
				
				static_assert( static_size >= 1, "vector must have at least two components." );
		};

		/**
		\relates nmn::math::vector
		Outputs a vector to an output stream.
		@param os The output ostream.
		@param vec The vector to output.
		@return A reference to the output stream.
		\author Sean Tromans
		*/
		template < typename Elem, typename Traits, size_t Size >
		inline std::basic_ostream< Elem, Traits > & operator << ( std::basic_ostream< Elem, Traits > & os, vector< bool, Size > const & vec );

		/**
		Component wise absolute equality check.
		@param lhs The first vector to compare.
		@param rhs The second vector to compare.
		@return true if the two vectors are exactly equal.
		\author Sean Tromans
		*/
		template < size_t Size >
		bool operator == ( vector< bool, Size > const & lhs, vector< bool, Size > const & rhs );

	};

};

#undef	NMN_MATH_VECTOR_CONSTRUCTOR

#endif	//NMN_TEMPLATES_MATH_VECTOR_BOOLEAN_HPP
